package com.xlh.util;

import com.xlh.exception.common.GlobalException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author zhr 2019/3/11
 */
public class FileUtil {

    private static Logger logger = LoggerFactory.getLogger(FileUtil.class);

    public static void createFile(String fileDir, String fileName) {
        createDir(fileDir);

        String filePath = StringUtils.join(fileDir, fileName);
        File file = new File(filePath);
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void createDir(String fileDir) {
        File dir = new File(fileDir);
        if (dir.exists()) {
            return;
        }
        if (!fileDir.endsWith(File.separator)) fileDir = fileDir + File.separator;

        dir.mkdirs();
    }

    /**
     * 写入文件,末尾自动添加\r\n
     * utf-8  追加
     * 默认直接创建新文件
     *
     * @param path
     * @param str
     */
    public static void writeLog(String path, String str) {
        writeLog(path, str, "utf-8");
    }

    /**
     * 写入文件,末尾自动添加\r\n
     * 默认直接创建新文件
     *
     * @param path
     * @param str
     */
    public static void writeLog(String path, String str, String encode) {
        writeLog(path, str, encode, false);
    }

    /**
     * 写入文件,末尾自动添加\r\n
     *
     * @param path     文件路径
     * @param str      写入文件内容
     * @param encode   编码格式
     * @param isAppend 是否追加文本
     */
    public static void writeLog(String path, String str, String encode, boolean isAppend) {
        File file = new File(path);
        try (FileOutputStream out = new FileOutputStream(file, isAppend)) {
            if (!file.exists()) file.createNewFile();
            StringBuffer sb = new StringBuffer();
            sb.append(str).append("\r\n");
            out.write(sb.toString().getBytes(encode));
            out.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 整个文件以string放回，添加\r\n换行
     *
     * @param path
     * @return
     */
    public static String readLogByString(String path) {
        return readLogByString(path, "utf-8");
    }

    /**
     * 加入编码
     * 整个文件以string放回，添加\r\n换行
     *
     * @param path
     * @return
     */
    public static String readLogByString(String path, String encode) {
        StringBuffer sb = new StringBuffer();
        String tempstr = null;
        try {
            File file = new File(path);
            if (!file.exists())
                throw new FileNotFoundException();
            FileInputStream fis = new FileInputStream(file);
            BufferedReader br = new BufferedReader(new InputStreamReader(fis, encode));
            while ((tempstr = br.readLine()) != null) {
                sb.append(tempstr + "\r\n");
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * utf-8编码
     * 按行读取文件，以list<String>的形式返回
     *
     * @param path
     * @return
     */
    public static List<String> readLogByList(String path) {
        return readLogByList(path, "utf-8");
    }

    /**
     * 按行读取文件，以list<String>的形式返回
     *
     * @param path
     * @return
     */
    public static List<String> readLogByList(String path, String encode) {
        List<String> lines = new ArrayList<String>();
        String tempstr = null;
        try {
            File file = new File(path);
            if (!file.exists()) {
                throw new FileNotFoundException();
            }
            FileInputStream fis = new FileInputStream(file);
            BufferedReader br = new BufferedReader(new InputStreamReader(fis, encode));
            while ((tempstr = br.readLine()) != null) {
                lines.add(tempstr);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return lines;
    }

    /**
     * 递归删除文件或者目录
     *
     * @param filePath
     */
    public static void deleteEveryThing(String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return;
            }
            if (file.isFile()) {
                file.delete();
            } else {
                File[] files = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    String root = files[i].getAbsolutePath();//得到子文件或文件夹的绝对路径
                    deleteEveryThing(root);
                }
                file.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * 得到一个文件夹下所有文件
     */
    public static List<String> getAllFileNameInFold(String fold_path) {
        List<String> file_paths = new ArrayList<String>();

        LinkedList<String> folderList = new LinkedList<String>();
        folderList.add(fold_path);
        while (folderList.size() > 0) {
            File file = new File(folderList.peekLast());
            folderList.removeLast();
            File[] files = file.listFiles();
            ArrayList<File> fileList = new ArrayList<File>();
            for (int i = 0; i < files.length; i++) {
                if (files[i].isDirectory()) {
                    folderList.add(files[i].getPath());
                } else {
                    fileList.add(files[i]);
                }
            }
            for (File f : fileList) {
                file_paths.add(f.getAbsoluteFile().getPath());
            }
        }
        return file_paths;
    }

    /**
     * 读取base64字符串为指定格式的文件
     * @param base64Info base64字符串,实践表明非图片格式也可以进行读取
     * @param picPath 服务器文件地址
     */
    public static void downloadBase64Pic(String base64Info, String picPath) {
        if (StringUtils.isEmpty(base64Info)) return;
        BASE64Decoder decoder = new BASE64Decoder();
        // 数据中： ...  在"base64,"之后的才是图片信息
        String[] arr = base64Info.split("base64,");
        OutputStream os = null;
        try {
            byte[] buffer = decoder.decodeBuffer(arr[1]);
            os = new FileOutputStream(picPath);
            os.write(buffer);

        } catch (IOException e) {
            logger.error("保存失败", e);
            throw new GlobalException("保存失败");
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    logger.error("下载base64图片,流关闭异常", e);
                }
            }
        }
    }

    /**
     * 将本地文件下载到客户端上
     *
     * @param response
     * @param filePath 文件路径（包含文件名称）
     * @param fileName 文件名称
     */
    public static void downloadFile(HttpServletResponse response, String filePath, String fileName) {
        ServletOutputStream out = null;
        FileInputStream inputStream = null;
        try {
            // 1.设置文件ContentType类型，这样设置，会自动判断下载文件类型
            response.setContentType("multipart/form-data");
            // 2.设置文件头：最后一个参数是设置下载文件名(假如我们叫a.pdf)
            response.setHeader("Content-Disposition", "attachment;fileName=" + new String(fileName.getBytes(), "ISO8859-1"));

            File file = new File(filePath);
            inputStream = new FileInputStream(file);
            // 3.通过response获取ServletOutputStream对象(out)
            out = response.getOutputStream();
            int b = 0;
            byte[] buffer = new byte[4 * 1024];
            while (b != -1) {
                b = inputStream.read(buffer);
                //4.写到输出流(out)中
                out.write(buffer, 0, b);
            }
            out.flush();
        } catch (IOException e) {
            logger.error("下载文件异常", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    logger.error("文件下载关闭闭异常", e);
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    logger.error("文件下载关闭闭异常", e);
                }
            }
        }
    }
    public static  File zipFiles(File[] srcFiles, File zipFile) {
        // 判断压缩后的文件存在不，不存在则创建
        if (!zipFile.exists()) {
            try {
                zipFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 创建 FileOutputStream 对象
        FileOutputStream fileOutputStream = null;
        // 创建 ZipOutputStream
        ZipOutputStream zipOutputStream = null;
        // 创建 FileInputStream 对象
        FileInputStream fileInputStream = null;

        try {
            // 实例化 FileOutputStream 对象
            fileOutputStream = new FileOutputStream(zipFile);
            // 实例化 ZipOutputStream 对象
            zipOutputStream = new ZipOutputStream(fileOutputStream);
            // 创建 ZipEntry 对象
            ZipEntry zipEntry = null;
            // 遍历源文件数组
            for (int i = 0; i < srcFiles.length; i++) {
                if (!"".equals(srcFiles[i])){
                // 将源文件数组中的当前文件读入 FileInputStream 流中
                fileInputStream = new FileInputStream(srcFiles[i]);
                // 实例化 ZipEntry 对象，源文件数组中的当前文件
                zipEntry = new ZipEntry(srcFiles[i].getName());
                zipOutputStream.putNextEntry(zipEntry);
                // 该变量记录每次真正读的字节个数
                int len;
                // 定义每次读取的字节数组
                byte[] buffer = new byte[1024];
                while ((len = fileInputStream.read(buffer)) > 0) {
                    zipOutputStream.write(buffer, 0, len);
                }
            }
            }
            zipOutputStream.closeEntry();
            zipOutputStream.close();
            fileInputStream.close();
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return zipFile;
    }
}
